const express = require("express");
const router = express.Router();
const path = require("path");
const pool = require("../pool.js");
const utils = require("../utils/index.js");
const utilsServer = require("../utils/serverInfo.js");
const moment = require("moment-timezone");
const multer = require("multer");
const AdmZip = require("adm-zip");
const AppInfoParser = require("app-info-parser");
const plist = require("plist");
const fs = require("fs");
const { readManifest } = require("node-aab-parser");
const msgUtils = require("../utils/feishu.js");
const crypto = require("crypto");
const CryptoJS = require("crypto-js");
const FormData = require("form-data");
const { exec } = require("child_process");
const config = require("../config");
const androidPublisherConn = require("../google/googleapis"); // './publisher' 是该文件的路径 
const axios = require("axios");
 
// identifier 'cinfig' has alreaby been declared
// 配置multer以使用本地磁盘存储
// 配置Multer以使用本地磁盘存储
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, "uploads/"); // 确保这个目录已经存在或者你在代码中创建它
    },
    filename: function (req, file, cb) {
        cb(null, Date.now() + "-" + file.originalname); // 使用日期时间来构建一个唯一的文件名
    },
});

const upload = multer({
    storage: storage, limits: {
        fileSize: 500 * 1024 * 1024, // 500MB（正确写法）
        // 不是 500 * 1000 * 1000（错误单位）
    }
});

const storage1 = multer.diskStorage({
    //ios第四步  根据类型 定义存储路径  服务器提取建好文件夹
    destination: function (req, file, cb) {
        let type = req.query.type;
        let address = "";
        if (type == "typeAI") {
            address = `/saveIosTypeAi-node`;
        } else if (type == "android-ins") {
            //ins2
            address = `/saveAndroidFile-node`;
        } else if (type == "android-tt") {
            address = `/saveAndroidFile-node`;
        } else if (type == "android-all") {
            address = `/saveAndroidAllFile-node`;
        } else if (type == "android-ins3" && dot == "apk") {
            address = `/saveAndroidIns3-node`;
        } else if (type == "android-ins3" && dot == "aab") {
            address = `/saveAndroidIns3-node`;
        } else if (type == "android-ins1") {
            address = `/saveAndroidIns1-node`;
        } else if (type == "ios-tt") {
            address = `/saveFile-node`;
        } else if (type == "ios-ins") {
            address = `/saveFile-node`;
        } else if (type == "pdf") {
            address = `/savePdfAndroidFile-node`;
        } else if (type == "remoteTV") {
            address = `/saveRemoteTV-node`;
        } else if (type == "wamr") {
            address = `/saveWamrFile-node`;
        } else if (type == "stepCounter") {
            address = `/saveStepCounterFile-node`;
        } else if (type == "calculator") {
            address = `/saveCalculatorLock-node`;
        } else if (type == "HeartRate") {
            address = `/saveFile`;
        } else if (type == "seamobitechRemote") {
            address = `/saveIosRokuRemoteNode`;
        } else if (type == "android-all2") {
            address = `/saveAndroidAll2File-node`;
        }
        else if (type == "universalControl") {
            address = `/saveUniversalControlNode`;
        }
        else if (type == "iosWa") {
            address = `/saveIosWaNode`;
        }
        else if (type == "android-roku2") {
            address = `/saveAndroidRoku2`;
        }
        else if (type == "android-roku3") {
            address = `/saveAndroidRoku3`;
        }
        else if (type == "android-Calorie") {
            address = `/saveAndroidCalorie`;
        }
        else if (type == "android-Print") {
            address = `/saveAndroidPrint`;
        }
        else if (type == "android-qr") {
            address = `/saveAndroidQr`;
        }
        else if (type == "iosQR") {
            address = `/saveIosQRNode`;
        }
        else if (type == "iosQR2") {
            address = `/saveIosQRNode2`;
        }
        else if (type == "iosBeauty") {
            address = `/saveIosBeautyNode`;
        }
        else if (type == "iosHeartPulse") {
            address = `/saveIosHeartPulseNode`;
        }
        else if (type == "universalRemote2") {
            address = `/saveIosUniversalRemote2Node`;
        }
        else if (type == "iosIns") {
            address = `/saveIosInsNode`;
        }
        else if (type == "AINote") {
            address = `/saveIosAINoteNode`;
        }
        else if (type == "iosTransir") {
            address = `/saveIosTransir`;
        }
        else if (type == "iosRecipeAI") {
            address = `/saveIosRecipeAINode`;
        }
        else if (type == "iosWithYou") {
            address = `/saveIosWithYouNode`;
        }
        else if (type == "iosMuseo") {
            address = `/saveIosMuseoNode`;
        }
        else if (type == "iosKOKO") {
            address = `/saveIosKOKO`;
        }
        // 设置文件上传目录
        cb(null, address);
    },
    filename: function (req, file, cb) {
        // 生成文件名
        cb(null, req.query.name);
    },
});

//公司人员id
//产品 582bb54a(于洋) g1eff8g3(曾佳依) c74b4g75(司浩轩)
//开发 269eceeg(黄伟杰) 48294a8b(陈继鹏)
//运营 39d85c67(朱晓明) 


const upload1 = multer({
    storage: storage1, limits: {
        fileSize: 500 * 1024 * 1024, // 500MB（正确写法）
        // 不是 500 * 1000 * 1000（错误单位）
    }
});
const uploadChunks = multer({ dest: 'uploads/chunks/' });
//分片上传
// 分片上传接口
router.post('/Chunks/upload', uploadChunks.single('chunk'), async (req, res) => {
    try {
        const { chunkIndex, totalChunks, uploadId, fileName } = req.body;
        const chunkFile = req.file;
        console.log(`接收分片 ${parseInt(chunkIndex) + 1}/${totalChunks}`);
        console.log('文件大小:', chunkFile.size);
        console.log('上传ID:', uploadId);
        // 创建上传目录
        const uploadDir = path.join('uploads', uploadId);
        if (!fs.existsSync(uploadDir)) {
            fs.mkdirSync(uploadDir, { recursive: true });
        }

        // 保存分片
        const chunkPath = path.join(uploadDir, `${fileName}.part${chunkIndex}`);
        fs.renameSync(chunkFile.path, chunkPath);

        console.log(`分片 ${parseInt(chunkIndex) + 1}/${totalChunks} 保存成功`);

        res.json({
            success: true,
            message: '分片上传成功',
            chunkIndex: parseInt(chunkIndex),
            totalChunks: parseInt(totalChunks)
        });

    } catch (error) {
        console.error('分片上传失败:', error);
        res.status(500).json({
            success: false,
            error: error.message
        });
      }
});

// 合并分片接口
router.post('/Chunks/merge', express.json(), async (req, res) => {
    try {
        const { uploadId, fileName, totalChunks, content } = req.body;
        const uploadDir = path.join('uploads', uploadId);
        const finalFilePath = path.join('uploads', fileName);

        // 保证流写完的 Promise
        function mergeChunksAndWaitDone() {
            return new Promise((resolve, reject) => {
                const writeStream = fs.createWriteStream(finalFilePath);

                writeStream.on('error', reject);
                writeStream.on('finish', resolve);

                // 注意同步顺序
                for (let i = 0; i < totalChunks; i++) {
                    const chunkPath = path.join(uploadDir, `${fileName}.part${i}`);
                    if (!fs.existsSync(chunkPath)) {
                        return reject(new Error(`分片 ${i} 不存在`));
                    }
                    const chunkBuffer = fs.readFileSync(chunkPath);
                    writeStream.write(chunkBuffer);
                    fs.unlinkSync(chunkPath);
                }
                writeStream.end();
            });
        }

        // 调用合并（同步写完再处理后续）
        await mergeChunksAndWaitDone();

        // 删除临时目录
        fs.rmdirSync(uploadDir);

        let uploaderName = 'admin';

        // 最保险：合并完后立刻检查下最终文件一定能读、且大于0
        if (!fs.existsSync(finalFilePath) || fs.statSync(finalFilePath).size === 0) {
            throw new Error('最终文件丢失或内容为空!');
        }

        // 推荐可以加一步校验，用 unzip -t 或 file 命令检测完整性
        // 如下（伪代码, 需要spawn同步执行）
        // const { execSync } = require('child_process');
        // execSync(`unzip -t "${finalFilePath}"`);

        console.log(`文件 ${fileName} 合并完成`);
        const result = await processFullUpload({
            filePath: finalFilePath,
            fileName,
            uploaderName,
            content: content || ''
        });

        res.send({ code: 0, msg: "success" });

    } catch (error) {
        console.error('文件合并失败:', error);
        res.status(500).json({ success: false, error: error.message });
    }
});


// 检查上传状态接口
router.get('/upload/status/:uploadId', (req, res) => {
    const { uploadId } = req.params;
    const uploadDir = path.join('uploads', uploadId);

    if (!fs.existsSync(uploadDir)) {
        return res.json({ uploadedChunks: 0 });
    }

    const files = fs.readdirSync(uploadDir);
    const uploadedChunks = files.filter(f => f.includes('.part')).length;

    res.json({ uploadedChunks });
});




router.post("/changeUpload", upload1.single("file"), async (req, res) => {
    res.send({
        code: 0,
        message: "上传成功",
    });
    console.log(
        "-----------------上传成功--------------",
        utils.formatDate(new Date()),
    );
});
router.post('/proxy/upload', (req, res) => {
    console.log('进入代理服务器')
    const options = {
        hostname: '45.76.212.42',
        port: 4000,
        path: '/node/uploadPackage/upload',
        method: 'POST',
        headers: req.headers
    };

    const proxyReq = http.request(options, (proxyRes) => {
        res.writeHead(proxyRes.statusCode, proxyRes.headers);
        proxyRes.pipe(res);
    });

    req.pipe(proxyReq);
});
// 创建文件上传的 POST 接口
router.post("/upload", upload.single("file"), async (req, res) => {
    console.log(utils.formatDate(new Date()), "-----------进入接口时间");
    let { name } = await utils.getUserInfo(req, res);
    //1. 收到文件 和 content
    let file = req.file;
    let content = req.body.content || '';
    let fileName = req.file.originalname;
    let dot = utils.getSubstringAfterLastDot(fileName);
    console.log(dot, "dot");
    let AppPackageUpload = {};
    //2. 获取并处理文件名以判断文件类型（aab, apk, ipa）
    const filePath = file.path;
    
    if (dot == "ipa") {

        const parser = new AppInfoParser(path.join(filePath));
        try {
            let result = await parser.parse();
            AppPackageUpload.id = utils.createId();
            AppPackageUpload.create_by = name;
            AppPackageUpload.update_by = name;
            AppPackageUpload.create_date = utils.formatDate(new Date());
            AppPackageUpload.update_date = utils.formatDate(new Date());
            AppPackageUpload.version = result.CFBundleShortVersionString;
            AppPackageUpload.version_code = result.CFBundleVersion;
            //ios第一步  拿到ios的CFBundleName 通过setTypeFromPackageName(result.CFBundleName) 去设置一个项目名
            console.log(result.CFBundleName,'1111111111111')
            AppPackageUpload.type = utils.setTypeFromPackageName(result.CFBundleName);
            AppPackageUpload.content = content;
            AppPackageUpload.env = dot;
            let iosName = utils.setTypeFromPackageName(result.CFBundleName) == 'seamobitechRemote' ? 'roku' : utils.setTypeFromPackageName(result.CFBundleName)
            AppPackageUpload.title = iosName + "-debug-" +
                result.CFBundleShortVersionString + "(" + result.CFBundleVersion + ")";
            AppPackageUpload.package_name = result.CFBundleIdentifier;
            // TODO: 上传文件到服务器逻辑
            // 根据type决定走哪台服务器的接口
            //ios第二步 

            let urlRequest = utils.getServerEndpointByType(AppPackageUpload.type, AppPackageUpload.type + '.ipa')
            let localFilePath = path.join("/home/wwwroot/default/node-server/", filePath)

            let uploadResponse = await uploadFileToServer(urlRequest, localFilePath);



            // let remotePath = await utilsServer.serverInfo(
            //   AppPackageUpload.type,
            //   path.join(filePath),
            //   utils.setTypeFromPackageName(result.CFBundleName) + ".ipa"
            // );

            // // remotePath 带域名 下载地址  存放路径
            // AppPackageUpload.file_path = remotePath;

            // TODO: 存到数据库
            const { text, values } = utils.createInsertSql(
                "js_app_package_upload",
                AppPackageUpload
            );
            let dbresult = await utils.query(text, values);
            if (dbresult.affectedRows !== 1) {
                throw new Error("数据库写入失败"); // 如果数据库写入不成功，则抛出错误
            }

            // TODO: 对接飞书通知
            debugNotice(AppPackageUpload.type, AppPackageUpload.title, AppPackageUpload.content);

            res.send({
                code: 0,
                msg: "success",
            });
        } catch (err) {
            console.log(err, "err");
            res.status(500).send(err);
        } finally {
            // 删除文件的逻辑放到finally块中，确保它总是被执行
            // if (filePath && fs.existsSync(filePath)) {
            //     fs.unlinkSync(filePath);
            // }
        }
    } else if (dot == "apk") {
        const parser = new AppInfoParser(path.join(filePath));
        try {
            let result = await parser.parse();
            AppPackageUpload.id = utils.createId();
            AppPackageUpload.create_by = name;
            AppPackageUpload.update_by = name;
            AppPackageUpload.create_date = utils.formatDate(new Date());
            AppPackageUpload.update_date = utils.formatDate(new Date());
            AppPackageUpload.package_name = result.package;
            AppPackageUpload.version = result.versionName;
            AppPackageUpload.version_code = result.versionCode;
            //安卓第一步 
            AppPackageUpload.type = utils.setTypeFromPackageName(result.package);
            AppPackageUpload.content = content;
            AppPackageUpload.env = dot;
            AppPackageUpload.title =
                utils.setTypeFromPackageName(result.package) +
                "-debug-" +
                result.versionName +
                "(" +
                result.versionCode +
                ")";
            // 根据type决定走哪台服务器的接口
            //安卓第二步 
            let urlRequest = utils.getServerEndpointByType(AppPackageUpload.type, AppPackageUpload.type + '.apk')
            console.log(urlRequest, '-------------------urlRequest------------------')
            let localFilePath = path.join("/home/wwwroot/default/node-server/", filePath)
            let uploadResponse = await uploadFileToServer(urlRequest, localFilePath);


            // TODO: 存到数据库
            const { text, values } = utils.createInsertSql(
                "js_app_package_upload",
                AppPackageUpload
            );
            let dbresult = await utils.query(text, values);
            if (dbresult.affectedRows !== 1) {
                throw new Error("数据库写入失败"); // 如果数据库写入不成功，则抛出错误
            }
            // TODO: 对接飞书通知
            //安卓第三步 
            debugNotice(
                AppPackageUpload.type,
                AppPackageUpload.title,
                AppPackageUpload.content
            );
            res.send({
                code: 0,
                msg: "success",
            });
        } catch (err) {
            console.log(err, "err");
            res.status(500).send(err);
        } finally {
            // 删除文件的逻辑放到finally块中，确保它总是被执行
            // if (filePath && fs.existsSync(filePath)) {
            //     fs.unlinkSync(filePath);
            // }
        }
    } else if (dot == "aab") {
        try {
            // let result = await readManifest(
            //   path.join("/home/wwwroot/default/node-server/", filePath)
            // );
            const absolutePath = path.resolve(
                "/home/wwwroot/default/node-server/",
                filePath
            );
            // 使用bundletool构建APKS文件包
            exec(
                `bundletool dump manifest --bundle="${absolutePath}"`,
                async (err, stdout, stderr) => {
                    if (err) {
                        // 当有错误发生时处理这里的逻辑
                        console.error("Error executing bundletool:", err);
                        if (filePath && fs.existsSync(filePath)) {
                            fs.unlinkSync(filePath);
                        }
                        res.status(500).send(err);
                        return;
                    }
                    if (stderr) {
                        // 输出可能的错误流
                        console.error("bundletool stderr:", stderr);
                    }
                    const packageMatch = stdout.match(/package="([^"]+)"/);
                    const versionCodeMatch = stdout.match(/versionCode="(\d+)"/);
                    const versionNameMatch = stdout.match(/versionName="([^"]+)"/);

                    // 根据正则表达式匹配的结果提取数据
                    const packageName = packageMatch ? packageMatch[1] : null;
                    const versionCode = versionCodeMatch ? versionCodeMatch[1] : null;
                    const versionName = versionNameMatch ? versionNameMatch[1] : null;
                    console.log(`Package Name: ${packageName}`);
                    console.log(`Version Code: ${versionCode}`);
                    console.log(`Version Name: ${versionName}`);
                    // 成功执行bundletool命令后的输出
                    // const parser = new AppInfoParser('/home/wwwroot/default/node-server/uploads/app.apks');
                    // let result = await parser.parse();
                    // console.log(result, "result")

                    AppPackageUpload.id = utils.createId();
                    AppPackageUpload.create_by = name;
                    AppPackageUpload.update_by = name;
                    AppPackageUpload.create_date = utils.formatDate(new Date());
                    AppPackageUpload.update_date = utils.formatDate(new Date());
                    AppPackageUpload.package_name = packageName;
                    AppPackageUpload.version = versionName;
                    AppPackageUpload.version_code = versionCode;
                    AppPackageUpload.type = utils.setTypeFromPackageName(packageName);
                    AppPackageUpload.content = content;
                    AppPackageUpload.env = dot;
                    AppPackageUpload.title =
                        utils.setTypeFromPackageName(packageName) +
                        "-release-" +
                        versionName +
                        "(" +
                        versionCode +
                        ")";

                    // TODO: 上传文件到服务器逻辑
                    let urlRequest = utils.getServerEndpointByType(AppPackageUpload.type, 'app-release.aab')
                    console.log(urlRequest, '-------------------urlRequest------------------')
                    let localFilePath = path.join("/home/wwwroot/default/node-server/", filePath)
                    let uploadResponse = await uploadFileToServer(urlRequest, localFilePath);





                    // let remotePath = await utilsServer.serverInfo(
                    //   AppPackageUpload.type,
                    //   path.join(filePath),
                    //   "app-release.aab"
                    // );
                    // AppPackageUpload.file_path = remotePath;
                    console.log(AppPackageUpload, "AppPackageUpload");
                    // TODO: 存到数据库
                    const { text, values } = utils.createInsertSql(
                        "js_app_package_upload",
                        AppPackageUpload
                    );
                    let dbresult = await utils.query(text, values);
                    if (dbresult.affectedRows !== 1) {
                        throw new Error("数据库写入失败"); // 如果数据库写入不成功，则抛出错误
                    }

                    // TODO: 对接飞书通知
                    submitFirstReviewRequest(
                        utils.getGroupIdByType(AppPackageUpload.type),
                        AppPackageUpload.type,
                        AppPackageUpload.package_name,
                        AppPackageUpload.title,
                        AppPackageUpload.content
                    );
                    res.send({
                        code: 0,
                        msg: "success",
                    });
                    if (filePath && fs.existsSync(filePath)) {
                        fs.unlinkSync(filePath);
                    }
                }
            );
        } catch (err) {
            console.log(err, "err");
            // if (filePath && fs.existsSync(filePath)) {
            //     fs.unlinkSync(filePath);
            // }
            res.status(500).send(err);
        } finally {
        }
    }
});
async function uploadFileToServer(url, filePath) {
    let datafile = new FormData();
    datafile.append("file", fs.createReadStream(filePath));

    const response = await axios.post(url, datafile, {
        timeout: 180000, // 设置超时时间为180秒
    });

    console.log(response.data, "上传文件响应数据");
    return response.data;
}
//查询列表
router.post("/findUploadPckageList", async (req, res) => {
    let user = await utils.getUserRole(req, res);
    let roleList = utils.filterUploadListByRoleKey(user.roleKey);
    if (user.roleAdmin || user.hasManage) {
        //是管理 无条件  查询所有
        roleList = [];
    }
    let { page, size } = utils.pageSize(req.body.page, req.body.size);

    const { type, dateRange } = req.body;
    let sql = `FROM js_app_package_upload WHERE status = 0`;

    let params = [];
    if (dateRange && dateRange.start && dateRange.end) {
        sql += ` AND update_date BETWEEN ? AND ?`;
        params.push(dateRange.start, dateRange.end);
    }

    // roleList 条件处理
    if (roleList.length > 0) {
        // 处理roleList, 转换成SQL查询语句中的IN子句
        const rolePlaceholders = roleList.map(() => "?").join(", "); // 创建占位符
        sql += ` AND type IN (${rolePlaceholders})`;
        params = params.concat(roleList); // 将roleList的值添加到参数列表中
    }

    // 统计总条数的SQL
    let sqlCount = `SELECT COUNT(*) AS total_count ${sql}`;
    // 查询数据的SQL
    let sqlSelect = `SELECT * ${sql} ORDER BY update_date DESC`;
    let { total } = await utils.getListSum(sqlCount, params, res, req);
    sqlSelect += ` LIMIT ? OFFSET ?`;
    params.push(size, page);
    await pool.query(sqlSelect, params, (err, result) => {
        if (err) return res.send(utils.returnData({ code: -1, err, req }));
        result.forEach((element) => {
            element.create_date = moment(element.create_date)
                .tz("Asia/Shanghai")
                .format("YYYY-MM-DD HH:mm:ss");
            element.update_date = moment(element.update_date)
                .tz("Asia/Shanghai")
                .format("YYYY-MM-DD HH:mm:ss");
        });
        res.send(
            utils.returnData({
                data: result,
                total: total,
            })
        );
    });
});

router.post("/challenge", async (req, res) => {
    let challengeObj = aesDecrypt(
        req.body.encrypt,
        createAESCipherKey("nztRyApIzRY3A0K8kRMATffICDrqB4rC")
    );
    let callbackObj = JSON.parse(challengeObj);
    if (challengeObj.includes("challenge")) {
        res.send({ challenge: callbackObj.challenge });
    }

    try {
        console.log(callbackObj, "callbackObjcallbackObjcallbackObjcallbackObj");

        let operatorId = callbackObj.event.operator.user_id.trim();

        let token = await msgUtils.getTenantAccessToken();

        //获取消息卡片信息 用以更新卡片
        let messageDtl = await msgUtils.getMessageDetails(
            token,
            callbackObj.event.context.open_message_id
        );

        let messageParse = JSON.parse(messageDtl.content);
        let buttonStr = callbackObj.event.action.value.value;
        let buttonType = callbackObj.event.action.value.type;
        let buttonPk = callbackObj.event.action.value.pk;
        let buttonGrayscale = callbackObj.event.action.value.grayscale;
        let buttonCode = callbackObj.event.action.value.code;
        let buttonTitle = callbackObj.event.action.value.title;
        let message_id = callbackObj.event.context.open_message_id;
        let buttonChat_id = callbackObj.event.context.open_chat_id;
        if (buttonStr == "success-1") {
            // const canAccess =
            //     (operatorId === "582bb54a") ||
            //     ((buttonPk === 'ins.freevideodownload.pro' ||
            //         buttonPk === 'download.video.downloader.videodownloader.instagram' ||
            //         buttonPk === 'download.video.downloader.videodownloader.mp4' ||
            //         buttonPk === 'roku.remote.control.tv.remotecontrol') &&
            //         operatorId === "269eceeg") ||
            //     (buttonPk === 'scan.qr.code.barcode.scanner' &&
            //         (operatorId === "582bb54a" ||
            //             operatorId === "48294a8b" ||
            //             operatorId === "g1eff8g3"))
            //     || (buttonPk === 'roku.remote.control.tv.remotecontrol' &&
            //         (operatorId === "582bb54a" ||
            //             operatorId === "48294a8b" || operatorId === "269eceeg"))

            //     ;
            //第一张卡片  点击了通过按钮
            //产品 582bb54a(于洋) g1eff8g3(曾佳依) c74b4g75(司浩轩)
            //开发 269eceeg(黄伟杰) 48294a8b(陈继鹏)
            //运营 39d85c67(朱晓明) 
            const buttonPksFor269 = [
                'ins.freevideodownload.pro',
                'download.video.downloader.videodownloader.instagram',
                'download.video.downloader.videodownloader.mp4',
                'roku.remote.control.tv.remotecontrol'
            ];
            // 这是你要“可被特定ID访问的包名列表”，Roku权限
            const rokuAllowedButtonPks = [
                'roku.remote.control.tv.remotecontrol',
                'roku.remote.control.tv.remoteforroku',
                'food.scanner.calorie.counter.cal.ai',
                'print.smart.printer.pdf.docs.scanner',
            ];
            const qrAllowedOperatorIds = ['582bb54a', '48294a8b', 'g1eff8g3'];
            const rokuAllowedOperatorIds = ['582bb54a', '48294a8b', '269eceeg'];

            // 主逻辑判断
            const canAccess =
                operatorId === "582bb54a" ||// 超级管理员
                (buttonPksFor269.includes(buttonPk) && operatorId === "269eceeg") ||// 某些按钮269可访问
                (buttonPk === 'scan.qr.code.barcode.scanner' && qrAllowedOperatorIds.includes(operatorId)) ||// 二维码专门权限
                (rokuAllowedButtonPks.includes(buttonPk) && rokuAllowedOperatorIds.includes(operatorId));// roku专门权限

            if (!canAccess) {
                //判断是不是产品点的
                // 前端 8d333cd2  产品（yu）582bb54a  运营(zhu) 39d85c67 运营(hai) 9c8364d1 运营(luo) 3581b3g8
                res.send({
                    toast: {
                        type: "error",
                        content: "你没有权限！",
                    },
                });
                return;
            } else {
                //是产品点的
                //创建更新卡片的模板
                // let data = constructCardData(messageParse);
                // // 更新卡片内容 使按钮不可点击
                // await msgUtils.updateCardDetails(
                //     token,
                //     data,
                //     callbackObj.event.context.open_message_id
                // );
                //点击了通过  创建下一个卡片 流转到运营  要把 buttonType(buttonType) 或者 buttonPk(ins.freevideodownload.pro) 带过去
                setTimeout(async () => {
                    let s = createOperationTransitionCard(
                        messageParse,
                        buttonType,
                        buttonPk,
                        buttonTitle,
                        message_id,
                        callbackObj.event.context.open_chat_id
                    );
                    await msgUtils.sendMessage(
                        callbackObj.event.context.open_chat_id,
                        "interactive",
                        s,
                        token
                    );
                });
                res.send({
                    toast: {
                        type: "success",
                        content: "通过成功！",
                    },
                });
            }
        } else if (buttonStr == "releaseClosedBeta-1") {
            // || operatorId != "269eceeg"
            //第一张卡片  点击了内测轨道

            // const canAccess =
            //     (operatorId === "582bb54a") ||
            //     ((buttonPk === 'ins.freevideodownload.pro' ||
            //         buttonPk === 'download.video.downloader.videodownloader.instagram' ||
            //         buttonPk === 'download.video.downloader.videodownloader.mp4' ||
            //         buttonPk === 'roku.remote.control.tv.remotecontrol') &&
            //         operatorId === "269eceeg") ||
            //     (buttonPk === 'scan.qr.code.barcode.scanner' &&
            //         (operatorId === "582bb54a" ||
            //             operatorId === "48294a8b" ||
            //             operatorId === "g1eff8g3"))
            //     || (buttonPk === 'roku.remote.control.tv.remotecontrol' &&
            //         (operatorId === "582bb54a" ||
            //             operatorId === "48294a8b" || operatorId === "269eceeg"))
            //     ;
            
            const buttonPksFor269 = [
                'ins.freevideodownload.pro',
                'download.video.downloader.videodownloader.instagram',
                'download.video.downloader.videodownloader.mp4',
                'roku.remote.control.tv.remotecontrol',
                
            ];
            // 这是你要“可被特定ID访问的包名列表”，Roku权限
            const rokuAllowedButtonPks = [
                'roku.remote.control.tv.remotecontrol',
                'roku.remote.control.tv.remoteforroku',
                'food.scanner.calorie.counter.cal.ai',
                'print.smart.printer.pdf.docs.scanner',

            ];
            const qrAllowedOperatorIds = ['582bb54a', '48294a8b', 'g1eff8g3'];
            const rokuAllowedOperatorIds = ['582bb54a', '48294a8b', '269eceeg'];

            // 主逻辑判断
            const canAccess =
                operatorId === "582bb54a" ||// 超级管理员
                (buttonPksFor269.includes(buttonPk) && operatorId === "269eceeg") ||// 某些按钮269可访问
                (buttonPk === 'scan.qr.code.barcode.scanner' && qrAllowedOperatorIds.includes(operatorId)) ||// 二维码专门权限
                (rokuAllowedButtonPks.includes(buttonPk) && rokuAllowedOperatorIds.includes(operatorId));// roku专门权限
            
            if (!canAccess) {
                //判断是不是产品点的
                // 前端 8d333cd2  产品（yu）582bb54a  运营(zhu) 39d85c67 运营(hai) 9c8364d1 运营(luo) 3581b3g8
                res.send({
                    toast: {
                        type: "error",
                        content: "你没有权限！",
                    },
                });
                return;
            } else {
                //有权限点击
                //创建更新卡片的模板
                //1. 更新卡片内容 使内测按钮不可点击
                // let data = constructCardDataBeta(
                //     messageParse,
                //     buttonType,
                //     buttonPk,
                //     buttonTitle
                // );
                // await msgUtils.updateCardDetails(
                //     token,
                //     data,
                //     callbackObj.event.context.open_message_id
                // );
                // 2. 先发个推送中的卡片 提示不要重复点击
                let loading = gpLoading();
                await msgUtils.sendMessage(
                    callbackObj.event.context.open_chat_id,
                    "interactive",
                    loading,
                    token
                );
                try {
                    //走发布 内测轨道流程  根据buttonType(buttonType) 或者 buttonPk(ins.freevideodownload.pro) 去判断通过哪个服务器去推送gp
                    // const result = await utils.deployGp(buttonType, 1, false);
                    // console.log("部署成功，返回结果:", result);
                    const result = await routeRequestBasedOnPackageName(buttonPk, buttonTitle, buttonType, message_id, buttonChat_id);
                    console.log(result, '内测轨道routeRequestBasedOnPackageName---------result')

                    if (result.code == 200) {

                        // 点击了内测轨道，创建卡片
                        let s = createBetaReleaseCard(
                            messageParse,
                            buttonType,
                            buttonPk,
                            buttonTitle
                        );
                        await msgUtils.sendMessage(
                            callbackObj.event.context.open_chat_id,
                            "interactive",
                            s,
                            token
                        );
                        res.send({
                            toast: {
                                type: "success",
                                content: "已发布至内测轨道！",
                            },
                        });
                    } else {
                        throw new Error(result.msg);
                    }
                } catch (error) {
                    console.error(
                        "部署失败:",
                        error,
                        "----------------------------------------------------err截至"
                    );

                    //  发送失败的卡片
                    let betaError = gpBetaError(error);
                    await msgUtils.sendMessage(
                        callbackObj.event.context.open_chat_id,
                        "interactive",
                        betaError,
                        token
                    );
                    // 部署失败 使卡片恢复点击效果

                    //更新卡片内容 让按钮恢复点击
                    setTimeout(async () => {
                        let dataRestore = constructCardDataRestore(
                            messageParse,
                            buttonType,
                            buttonPk,
                            buttonTitle
                        );
                        await msgUtils.updateCardDetails(
                            token,
                            dataRestore,
                            callbackObj.event.context.open_message_id
                        );
                    });

                    res.send({
                        toast: {
                            type: "error",
                            content: "内测轨道发布失败",
                        },
                    });
                }
            }
        } else if (buttonStr == "success-2") {
            //第二张卡片的通过 只有运营能点
            if (
                operatorId != "39d85c67" ||
                operatorId != "9c8364d1" ||
                operatorId != "74d698f2" ||
                operatorId != "3581b3g8"
            ) {
                // 前端 8d333cd2  产品（yu）582bb54a  运营(zhu) 39d85c67 运营(hai) 9c8364d1 运营(luo) 3581b3g8
                res.send({
                    toast: {
                        type: "error",
                        content: "你没有权限！",
                    },
                });
                return;
            } else {
                //运营点击了通过 callbackObj.event.action.value 可以判断是哪个包 要发布
                /* callbackObj.event.action.value{
                pk: 'ins.freevideodownload.pro',
                type: 'android-ins',
                value: 'success-2'
                }*/

                res.send({ code: 0 });
            }
        } else if (buttonStr == "cancel-2") {
            // 第二张 流转到运营的卡片  撤销    //只有产品能点击撤销
            if (operatorId != "582bb54a" || operatorId != "269eceeg" || operatorId != "269eceeg") {
                //判断是不是产品点的
                // 前端 8d333cd2  产品（yu）582bb54a  运营(zhu) 39d85c67 运营(hai) 9c8364d1 运营(luo) 3581b3g8
                res.send({
                    toast: {
                        type: "error",
                        content: "你没有权限！",
                    },
                });
                return;
            } else {
                console.log("点击了撤销", callbackObj);
                //点击了撤销 把消息信息入库
                let cancelObj = {};
                cancelObj.id = utils.createId();
                cancelObj.message_id = callbackObj.event.context.open_message_id;
                cancelObj.status = 1;
                console.log(cancelObj, "cancelObjcancelObj");
                const { text, values } = utils.createInsertSql(
                    "js_app_msg_status",
                    cancelObj
                );
                let result = await utils.query(text, values);
                console.log(result, "result");

                //产品点击了撤销
                let data = constructCardDataTwo(messageParse);
                // 更新卡片内容 使按钮不可点击
                await msgUtils.updateCardDetails(
                    token,
                    data,
                    callbackObj.event.context.open_message_id
                );
                setTimeout(async () => {
                    //点击了撤销  创建撤销卡片
                    let s = createRevokeCard(messageParse);
                    await msgUtils.sendMessage(
                        callbackObj.event.context.open_chat_id,
                        "interactive",
                        s,
                        token
                    );
                });

                res.send({
                    toast: {
                        type: "success",
                        content: "撤销成功！",
                    },
                });
            }
        } else if (buttonStr == "pause") {
            if (
                operatorId != "582bb54a" ||
                operatorId != "39d85c67" ||
                operatorId != "9c8364d1" ||
                operatorId != "3581b3g8" ||
                operatorId != "269eceeg"
            ) {
                //判断是不是产品点的
                // 前端 8d333cd2  产品（yu）582bb54a  运营(zhu) 39d85c67 运营(hai) 9c8364d1 运营(luo) 3581b3g8
                res.send({
                    toast: {
                        type: "error",
                        content: "你没有权限！",
                    },
                });
                return;
            } else {
                //去处理暂停阶段性发布
                pausePeriodicRelease(
                    buttonType,
                    buttonPk,
                    buttonTitle,
                    buttonGrayscale,
                    buttonCode,
                    buttonChat_id,
                    message_id,
                    messageParse
                );
                res.send({ code: 0 });
            }
        }
    } catch (error) {
        console.log(error);
    }
});
// function traverseAndTranslate(node) {
//     console.log(node.nodeType)
//     if (node.nodeType === Node.TEXT_NODE) {
//         const originalText = node.nodeValue.trim();
//         if (originalText.length > 0) {  // 确保有文本存在
//             const translatedNode = document.createTextNode(` (翻译后)`);
//             node.parentNode.insertBefore(translatedNode, node.nextSibling);
//         }

//     } else if (node.nodeType === Node.ELEMENT_NODE) {
//         node.childNodes.forEach(child => traverseAndTranslate(child));
//     }
// }

// // 开始翻译整个文档
// traverseAndTranslate(document.body);  // 将'es'替换为你的目标语言代码
async function debugNotice(downUrltype, title, content) {
    console.log(downUrltype, 'downUrltype')
    let token = await msgUtils.getTenantAccessToken();
    let msg_type = "interactive";
    //ios第三步 根据type 决定通知到哪个飞书群 以及下载网页
    let id = utils.getGroupIdByType(downUrltype);
    let at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    if (downUrltype == 'iosWa' || downUrltype == 'iosQR' || downUrltype == 'iosQR2' || downUrltype == 'iosWithYou') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"g1eff8g3\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'android-qr' || downUrltype == 'iosTransir' || downUrltype == 'iosRecipeAI' || downUrltype == 'iosKOKO') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"g1eff8g3\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'android-Calorie') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"c74b4g75\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'android-Print') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'iosBeauty') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"c74b4g75\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'iosHeartPulse') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"c74b4g75\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'universalRemote2') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'AINote') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"c74b4g75\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }
    if (downUrltype == 'iosIns') {
        at = `<at id=\\"582bb54a\\">(产品)</at><at id=\\"c74b4g75\\">(产品)</at><at id=\\"5bfbfa32\\">(测试)</at><at id=\\"c47a29d7\\">(测试)</at>`
    }

    let contentMsg = `{
  "config":{"wide_screen_mode":true},
  "elements":[
    {"tag":"div","text":{"content":"发布时间:${utils.formatDate(
        new Date()
    )}\\n${at}\\n${content}","tag":"lark_md"},"extra":{"alt":{"content":"","tag":"plain_text"},"img_key":"img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg","tag":"img"}},
    {"actions":[
      {"tag":"button","text":{"content":"下载","tag":"plain_text"},
   "type":"primary","url":"${utils.getDownloadPageByType(
        downUrltype
    )}"}],"tag":"action"}],
   "header":{"template":"blue","title":{"content":"${title}","tag":"plain_text"}}}`;
    await msgUtils.sendMessage(id, msg_type, contentMsg, token);
}
//正式包发布的第一次卡片审核申请---  通过 和 推内测通道  只有产品有权限点
async function submitFirstReviewRequest(
    groupId,
    buttonType,
    pk,
    title,
    content
) {
    let token = await msgUtils.getTenantAccessToken();
    let msg_type = "interactive";
    // let id = "oc_09f086e1bc825f4bbd70a162b4d08f58";
    let id = groupId;
    let at = `<at id="582bb54a">(产品)</at>`
    if (buttonType == 'android-all' || buttonType == 'android-ins' || buttonType == 'android-roku2') {
        at = `<at id="582bb54a">(产品)</at><at id="269eceeg">(研发)</at>`
    }
    if (buttonType == 'android-roku2' || buttonType == 'android-roku3' ) {
        at = `<at id="582bb54a">(产品)</at><at id="269eceeg">(研发)</at><at id="48294a8b">(研发)</at>`
    }
    if (buttonType == 'android-Calorie') {
        at = `<at id="582bb54a">(产品)</at><at id="c74b4g75">(产品)</at><at id="48294a8b">(研发)</at>`
    }
    if (buttonType == 'android-Print') {
        at = `<at id="582bb54a">(产品)</at><at id="269eceeg">(研发)</at><at id="48294a8b">(研发)</at>`
    }
    if (buttonType == 'android-qr') {
        at = `<at id="582bb54a">(产品)</at><at id="g1eff8g3">(产品)</at><at id="48294a8b">(研发)</at>`
    }
    if (!content) {
        content = ' '
    }
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `发布时间:${utils.formatDate(
                        new Date()
                    )}\n\n请审核:\n${at}\n${content || " "}`,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
            {
                actions: [
                    {
                        tag: "button",
                        text: { content: "通过", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,
                        value: {
                            value: "success-1",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认通过吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                    {
                        tag: "button",
                        text: { content: "内测轨道", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,
                        value: {
                            value: "releaseClosedBeta-1",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认发布到内测轨道吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                ],
                tag: "action",
            },
        ],
        header: {
            template: "blue",
            title: { content: `${title}   等待审核`, tag: "plain_text" },
        },
    };

    let jsonString = JSON.stringify(contentMsg);
    await msgUtils.sendMessage(id, msg_type, jsonString, token);
}
function aesDecrypt(encryptedData, key) {
    const encryptedBuffer = Buffer.from(encryptedData, "base64");
    const iv = encryptedBuffer.slice(0, 16);
    const data = encryptedBuffer.slice(16);
    const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
    let decrypted = decipher.update(data, "binary", "utf8");
    decrypted += decipher.final("utf8");
    return decrypted;
}
function createAESCipherKey(key) {
    const hash = crypto.createHash("sha256");
    hash.update(key);
    return hash.digest();
}

//创建更新第一个卡片信息
function constructCardData(messageParse) {
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at>\n${messageParse.elements[0][2].text}`,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
            {
                actions: messageParse.elements[1].map((action) => ({
                    tag: "button",
                    text: { content: action.text, tag: "plain_text" },
                    type: action.type,
                    disabled: true,
                    disabled_tips: { tag: "plain_text", content: "" },
                    complex_interaction: true,
                    value: action.value,
                    confirm: {
                        title: { tag: "plain_text", content: `确认${action.text}吗？` },
                        text: { tag: "plain_text", content: "点击确定以继续操作。" },
                    },
                })),
                tag: "action",
            },
        ],
        header: {
            template: "blue",
            title: { content: messageParse.title, tag: "plain_text" },
        },
    };

    let jsonString = JSON.stringify(contentMsg);
    let data = {
        content: jsonString,
    };

    return data;
}
//只让内测通道按钮不可点击
function constructCardDataBeta(messageParse, buttonType, pk, title) {
    let contentText = `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at>${messageParse.elements[0][2].text}`
    if (buttonType == 'android-all') {
        contentText = `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at><at id="269eceeg">(研发)</at>${messageParse.elements[0][3].text}`
    }
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at>${messageParse.elements[0][2].text}`,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
            {
                actions: [
                    {
                        tag: "button",
                        text: { content: "通过", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,

                        value: {
                            value: "success-1",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认通过吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                    {
                        tag: "button",
                        text: { content: "内测轨道", tag: "plain_text" },
                        type: "primary",
                        disabled: true,
                        disabled_tips: { tag: "plain_text", content: "不可用" },
                        complex_interaction: true,
                        value: {
                            value: "releaseClosedBeta-1",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认发布到内测轨道吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                ],
                tag: "action",
            },
        ],
        header: {
            template: "blue",
            title: { content: messageParse.title, tag: "plain_text" },
        },
    };

    let jsonString = JSON.stringify(contentMsg);
    let data = {
        content: jsonString,
    };

    return data;
}

//内测轨道发布失败  恢复卡片按钮点击
function constructCardDataRestore(messageParse, buttonType, pk, title) {
    let contentText = `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at>${messageParse.elements[0][2].text}`
    if (buttonType == 'android-all') {
        contentText = `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at><at id="269eceeg">(研发)</at>${messageParse.elements[0][3].text}`
    }
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: contentText,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
            {
                actions: [
                    {
                        tag: "button",
                        text: { content: "通过", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,
                        value: {
                            value: "success-1",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认通过吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                    {
                        tag: "button",
                        text: { content: "内测轨道", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,
                        value: {
                            value: "releaseClosedBeta-1",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认发布到内测轨道吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                ],
                tag: "action",
            },
        ],
        header: {
            template: "blue",
            title: { content: messageParse.title, tag: "plain_text" },
        },
    };

    let jsonString = JSON.stringify(contentMsg);
    let data = {
        content: jsonString,
    };

    return data;
}

//创建更新第二个卡片信息-撤销发布
function constructCardDataTwo(messageParse) {
    let textElements = messageParse.elements[0].filter(
        (element) => element.tag === "text"
    );
    // 新数组的最后一项 --  取到更新内容
    let lastTextElement = textElements[textElements.length - 1];

    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="9c8364d1">(运营)</at><at id="3581b3g8">(运营)</at>${lastTextElement.text}`,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
            {
                actions: messageParse.elements[1].map((action) => ({
                    tag: "button",
                    text: { content: action.text, tag: "plain_text" },
                    type: action.type,
                    disabled: true,
                    disabled_tips: { tag: "plain_text", content: "" },
                    complex_interaction: true,
                    value: action.value,
                    confirm: {
                        title: { tag: "plain_text", content: `确认${action.text}吗？` },
                        text: { tag: "plain_text", content: "点击确定以继续操作。" },
                    },
                })),
                tag: "action",
            },
        ],
        header: {
            template: "blue",
            title: { content: messageParse.title, tag: "plain_text" },
        },
    };

    let jsonString = JSON.stringify(contentMsg);
    let data = {
        content: jsonString,
    };

    return data;
}

// 创建更新暂停发布的卡片 -使其不可点击
// function pauseCardDataTwo(messageParse) {
//   let textElements = messageParse.elements[0].filter(
//     (element) => element.tag === "text"
//   );
//   // 新数组的最后一项 --  取到更新内容
//   let lastTextElement = textElements[textElements.length - 1];

//   let contentMsg = {
//     config: { wide_screen_mode: true, update_multi: true },
//     elements: [
//       {
//         tag: "div",
//         text: {
//           content: `${messageParse.elements[0][0].text}<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="9c8364d1">(运营)</at><at id="3581b3g8">(运营)</at>${lastTextElement.text}`,
//           tag: "lark_md",
//         },
//         extra: {
//           alt: { content: "", tag: "plain_text" },
//           img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
//           tag: "img",
//         },
//       },
//       {
//         actions: messageParse.elements[1].map((action) => ({
//           tag: "button",
//           text: { content: action.text, tag: "plain_text" },
//           type: action.type,
//           disabled: true,
//           disabled_tips: { tag: "plain_text", content: "" },
//           complex_interaction: true,
//           value: action.value,
//           confirm: {
//             title: { tag: "plain_text", content: `确认${action.text}吗？` },
//             text: { tag: "plain_text", content: "点击确定以继续操作。" },
//           },
//         })),
//         tag: "action",
//       },
//     ],
//     header: {
//       template: "blue",
//       title: { content: messageParse.title, tag: "plain_text" },
//     },
//   };

//   let jsonString = JSON.stringify(contentMsg);
//   let data = {
//     content: jsonString,
//   };

//   return data;
// }

//流转到运营的卡片
function createOperationTransitionCard(
    messageParse,
    buttonType,
    pk,
    title,
    message_id,
    chat_id
) {
    let str = messageParse.title.slice(0, -4);
    str = str + "--等待发布";
    let at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at>`
    if (buttonType == 'android-qr') { //鲁齐74d698f2
        at = `<at id="582bb54a">(产品)</at><at id="g1eff8g3">(产品)</at><at id="39d85c67">(运营)</at><at id="74d698f2">(运营)</at>`
    }
    if (buttonType == 'android-roku2' || buttonType == 'android-roku3' ) {//罗可以3581b3g8  雪薇 1624e4g5
        at = `<at id="582bb54a">(产品)</at> <at id="39d85c67">(运营)</at><at id="74d698f2">(运营)</at>`
    }
    if (buttonType == 'android-Calorie') {//罗可以3581b3g8  雪薇 1624e4g5
        at = `<at id="582bb54a">(产品)</at><at id="c74b4g75">(产品)</at> <at id="39d85c67">(运营)</at><at id="74d698f2">(运营)</at>`
    }
    if (buttonType == 'android-Print') {//罗可以3581b3g8  雪薇 1624e4g5
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="74d698f2">(运营)</at>`
    }
    console.log(messageParse.elements[0], 'messageParse.elements[0]')
    console.log(messageParse.elements[0][2], 'messageParse.elements[0][2]')
    console.log(messageParse.elements[0][3], 'messageParse.elements[0][3]')
    let contentx = messageParse.elements[0][2].text ? messageParse.elements[0][2].text : messageParse.elements[0][3].text
    if (!contentx) {
        contentx = ' '
    }
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `${messageParse.elements[0][0].text}${at}${contentx || ' '}`,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
            {
                actions: [
                    {
                        tag: "button",
                        text: { content: "通过", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,
                        value: {
                            value: "success-2",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        multi_url: {
                            url: `https://insdoss.freeapptools.com/saveFile/Grayscale.html?pk=${pk}&type=${buttonType}&title=${title}&message_id=${message_id}&chat_id=${chat_id}`,
                            pc_url: "",
                            ios_url: "",
                            android_url: "",
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认通过吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                    {
                        tag: "button",
                        text: { content: "撤销", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,
                        value: {
                            value: "cancel-2",
                            type: buttonType,
                            pk: pk,
                            title: title,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认撤销吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                ],
                tag: "action",
            },
        ],
        header: {
            template: "blue",
            title: { content: str, tag: "plain_text" },
        },
    };

    let jsonString = JSON.stringify(contentMsg);

    return jsonString;
}

//创建发布内测轨道的卡片
function createBetaReleaseCard(messageParse, buttonType, pk, title) {
    console.log(JSON.stringify(messageParse))
    let elementValue = messageParse.elements[0][2].text || messageParse.elements[0][3].text || messageParse.elements[0][4].text || ' ';
    let str = messageParse.title.slice(0, -4);
    str = str + "已发布到内测轨道";
    let msgContent = `发布时间:${utils.formatDate(
        new Date()
    )}\n<at id="582bb54a">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
        }`;
    if (buttonType == "android-all") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
            }\n内测链接:\nhttps://play.google.com/apps/internaltest/4701685560027064094`;
    }
    if (buttonType == "android-all2") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
            }\n内测链接:\nhttps://play.google.com/apps/internaltest/4701287120062732773`;
    }
    if (buttonType == "android-ins") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
            }\n内测链接:\nhttps://play.google.com/apps/internaltest/4701671940936246967`;
    }
    if (buttonType == "android-roku2") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
            }\n内测链接:\nhttps://play.google.com/apps/internaltest/4701004214712939674`;
    }
    if (buttonType == "android-roku3") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
        }\n内测链接:\nhttps://play.google.com/apps/internaltest/4700562773151803756`;
    }
    if (buttonType == "android-Calorie") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="c74b4g75">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
        }\n内测链接:\nhttps://play.google.com/apps/internaltest/4701589737819091098`;
    }
    if (buttonType == "android-Print") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
            }\n内测链接:\nhttps://play.google.com/apps/internaltest/4700820772732796732`;
    }
    if (buttonType == "android-qr") {
        msgContent = `发布时间:${utils.formatDate(
            new Date()
        )}\n<at id="582bb54a">(产品)</at><at id="g1eff8g3">(产品)</at><at id="5bfbfa32">(测试)</at><at id="c47a29d7">(测试)</at>\n${elementValue
            }\n内测链接:\nhttps://play.google.com/apps/internaltest/4701730199445026090`;
    }

    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: msgContent,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
        ],
        header: {
            template: "blue",
            title: { content: str, tag: "plain_text" },
        },
    };
    // 根据 'type' 的值来决定是否添加按钮
    if (buttonType == "android-all") {
        let buttonElement = {
            actions: [
                {
                    tag: "button",
                    text: { content: "跳转内测链接", tag: "plain_text" },
                    type: "primary",
                    complex_interaction: true,
                    value: {
                        value: "Jump",
                        type: buttonType,
                        pk: pk,
                        title: title,
                    },
                    multi_url: {
                        url: `https://play.google.com/apps/internaltest/4701685560027064094`,
                        pc_url:
                            "https://play.google.com/apps/internaltest/4701685560027064094",
                        ios_url:
                            "https://play.google.com/apps/internaltest/4701685560027064094",
                        android_url:
                            "https://play.google.com/apps/internaltest/4701685560027064094",
                    },
                },
            ],
            tag: "action",
        };
        // 将按钮元素添加到 elements 数组中
        contentMsg.elements.push(buttonElement);
    }
    if (buttonType == "android-ins") {
        let buttonElement = {
            actions: [
                {
                    tag: "button",
                    text: { content: "跳转内测链接", tag: "plain_text" },
                    type: "primary",
                    complex_interaction: true,
                    value: {
                        value: "Jump",
                        type: buttonType,
                        pk: pk,
                        title: title,
                    },
                    multi_url: {
                        url: `https://play.google.com/apps/internaltest/4701671940936246967`,
                        pc_url:
                            "https://play.google.com/apps/internaltest/4701671940936246967",
                        ios_url:
                            "https://play.google.com/apps/internaltest/4701671940936246967",
                        android_url:
                            "https://play.google.com/apps/internaltest/4701671940936246967",
                    },
                },
            ],
            tag: "action",
        };
        // 将按钮元素添加到 elements 数组中
        contentMsg.elements.push(buttonElement);
    }
    let jsonString = JSON.stringify(contentMsg);

    return jsonString;
}
//创建  内测轨道发布中。。
function gpLoading() {
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `内测轨道发布中...`,
                    tag: "lark_md",
                },
            },
        ],
    };

    let jsonString = JSON.stringify(contentMsg);
    return jsonString;
}

//内测推送失败卡片
function gpBetaError(error) {
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `内测轨道发布失败:\n${removeAnsiColorCodes(error)}`,
                    tag: "lark_md",
                },
            },
        ],
    };

    let jsonString = JSON.stringify(contentMsg);
    return jsonString;
}
function removeAnsiColorCodes(str) {
    let cleanStr = str.replace(/\x1b\[[0-9;]*m/g, ""); // 移除ANSI颜色代码
    cleanStr = cleanStr.replace(/^STDERR:\s*/g, ""); // 移除开始处的'STDERR:'
    cleanStr = cleanStr.replace(/\[!\]\s*/g, ""); // 移除'[!]'和后面可能的空白
    return cleanStr;
}
//正式pro推送卡片
function gpProMsg(msg) {
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `${msg}`,
                    tag: "lark_md",
                },
            },
        ],
    };

    let jsonString = JSON.stringify(contentMsg);
    return jsonString;
}
//创建发布撤销的卡片
function createRevokeCard(messageParse) {
    let textElements = messageParse.elements[0].filter(
        (element) => element.tag === "text"
    );
    // 新数组的最后一项 --  取到更新内容
    let lastTextElement = textElements[textElements.length - 1];
    let str = messageParse.title.slice(0, -4);
    str = str + "已撤销发布";
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `撤销时间:${utils.formatDate(
                        new Date()
                    )}\n<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="9c8364d1">(运营)</at><at id="3581b3g8">(运营)</at>${lastTextElement.text
                        }`,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
        ],
        header: {
            template: "blue",
            title: { content: str, tag: "plain_text" },
        },
    };

    let jsonString = JSON.stringify(contentMsg);

    return jsonString;
}
//产品 582bb54a(于洋) g1eff8g3(曾佳依) c74b4g75(司浩轩)
//开发 269eceeg(黄伟杰) 48294a8b(陈继鹏)
//运营 39d85c67(朱晓明) 
//创建触发阈值的卡片
async function checkThresholdLimit(appNotice) {
    let token = await msgUtils.getTenantAccessToken();
    let msg_type = "interactive";
    let id = utils.getGroupIdByType(appNotice.type);
    let at = "";
    let displayThreshold = (appNotice.type === "android-Print") ? 50 : 100;
    if (appNotice.type == "android-ins" || appNotice.type == "android-all" || appNotice.type == "android-all2") {
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="269eceeg">(研发)</at>`;
    }
    if (appNotice.type == "android-roku2") {
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="269eceeg">(研发)</at><at id="48294a8b">(研发)</at>`;
    }
    if (appNotice.type == "android-roku3" ) {
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="269eceeg">(研发)</at><at id="48294a8b">(研发)</at>`;
    }
    if ( appNotice.type == "android-Calorie") {
        at = `<at id="582bb54a">(产品)</at><at id="c74b4g75">(产品)</at><at id="39d85c67">(运营)</at><at id="48294a8b">(研发)</at>`;
    }
    if (appNotice.type == "android-Print") {
        at = `<at id="582bb54a">(产品)</at><at id="269eceeg">(研发)</at><at id="39d85c67">(运营)</at><at id="48294a8b">(研发)</at>`;
    }
    if (appNotice.type == "packageName") {
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="269eceeg">(研发)</at>`;
    }
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `触发阈值时间:${moment(
                        appNotice.update_time
                    )
                        .tz("Asia/Shanghai")
                        .format("YYYY-MM-DD HH:mm:ss")}\n\n${at}\n\n 用户更新数量达到:${displayThreshold}`,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
        ],
        header: {
            template: "green",
            title: {
                content: `${appNotice.type}-versionCode:(${appNotice.ver})`,
                tag: "plain_text",
            },
        },
    };

    let jsonString = JSON.stringify(contentMsg);
    await msgUtils.sendMessage(id, msg_type, jsonString, token);
}
//创建分阶段发布成功的卡片
function gpProMsgCard(body, title, grayscale, code) {
    let at = "";
    if (body.type == "android-ins" || body.type == "android-all" || body.type == "android-all2" || body.type == "android-roku2") {
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at>`;
    }
    if (body.type == "android-qr") { //g1eff8g3 增加一 
        at = `<at id="582bb54a">(产品)</at><at id="g1eff8g3">(产品)</at><at id="39d85c67">(运营)</at>`;
    }
    if (body.type == "android-roku2" || body.type == "android-roku3"  ) {
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at>`;
    }
    if (body.type == "android-Calorie") {
        at = `<at id="582bb54a">(产品)</at><at id="c74b4g75">(产品)</at><at id="39d85c67">(运营)</at>`;
    }
    if (body.type == "android-Print") {
        at = `<at id="582bb54a">(产品)</at><at id="39d85c67">(运营)</at><at id="269eceeg">(研发)</at><at id="48294a8b">(研发)</at>`;
    }
    let content = `版本发布时间:${utils.formatDate(new Date())}\n${at}\n${title}-分阶段发布:(${grayscale})-成功！`
    if (grayscale == '1') {
        content = `版本发布时间:${utils.formatDate(new Date())}\n${at}\n${title}-全量发布成功！`
    }
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: content,
                    tag: "lark_md",
                },
                extra: {
                    alt: { content: "", tag: "plain_text" },
                    img_key: "img_v2_f4f6fa23-e931-4dae-8ea2-c3d398656ddg",
                    tag: "img",
                },
            },
            {
                actions: [
                    {
                        tag: "button",
                        text: { content: "暂停分阶段发布", tag: "plain_text" },
                        type: "primary",
                        complex_interaction: true,
                        value: {
                            value: "pause",
                            type: body.type,
                            pk: body.pk,
                            title: body.title,
                            grayscale: grayscale,
                            code: code,
                        },
                        confirm: {
                            title: { tag: "plain_text", content: "确认暂停吗？" },
                            text: { tag: "plain_text", content: "" },
                        },
                    },
                ],
                tag: "action",
            },
        ],
        header: {
            template: "blue",
            title: {
                content: `${title}`,
                tag: "plain_text",
            },
        },
    };

    let jsonString = JSON.stringify(contentMsg);
    return jsonString;
}

//暂停成功的卡片
function gpPauseCard(title) {
    let contentMsg = {
        config: { wide_screen_mode: true, update_multi: true },
        elements: [
            {
                tag: "div",
                text: {
                    content: `暂停分阶段发布成功:\n${title} - 灰度 (${grayscale})`,
                    tag: "lark_md",
                },
            },
        ],
    };

    let jsonString = JSON.stringify(contentMsg);
    return jsonString;
}

//内测轨道 根据包名不同选择不同服务器的接口
async function routeRequestBasedOnPackageName(pk, title, type, message_id, chat_id) {
    let query = {
        pk: pk,
        title: title,
        type: type,
        message_id: message_id,
        chat_id: chat_id,
    }
    let urlRequest = "";
    switch (pk) {
        case config.INS1:
            urlRequest =
                "http://45.76.212.42:5000/node/uploadPackage/pushLocalPackageToGooglePlayInternalTrack";
            break;
        case config.INS2:
        case config.ALL:
        case config.ALL2:
        case config.androidRoku2:
        case config.androidRoku3:
        case config.androidCalorie:
        case config.androidQr:
        case config.androidPrint:
            urlRequest =
                "http://170.187.230.149:5000/node/uploadPackage/pushLocalPackageToGooglePlayInternalTrack";
            break;
        case config.PDF:
        case config.INS3:
        case config.STEPCOUNTER:
        case config.WA2:
        case config.WA3:
            urlRequest =
                "http://172.104.35.128:5000/node/uploadPackage/pushLocalPackageToGooglePlayInternalTrack";
            break;
        case config.CALCULATOR:
            urlRequest =
                "https://tp.seamobitech.com/node/uploadPackage/pushLocalPackageToGooglePlayInternalTrack";
            break;
        case config.CHAT1:
        case config.CHAT2:
        case config.CHAT5:
            urlRequest =
                "http://139.177.190.31:5000/node/uploadPackage/pushLocalPackageToGooglePlayInternalTrack";
            break;
        default:
            console.info("Package name does not match any known keys");
            return null;
    }
    if (urlRequest) {
        try {
            const response = await axios.post(urlRequest, query, {
                headers: {
                    "Content-Type": "application/json",
                },
                timeout: 180000, // 设置超时时间为180秒
            });
            return response.data;
        } catch (error) {
            console.error("request error please view log:", error.message);
            return { code: -1, msg: error.message };
        }
    } else {
        console.error("urlRequest is empty.");
        return { code: -1, msg: "urlRequest is empty" };
    }

}
router.post("/pushLocalPackageToGooglePlayInternalTrack", async (req, res) => {
    let token = await msgUtils.getTenantAccessToken();
    console.log(req.body, "我是pushLocalPackageToGooglePlayInternalTrack--------我在", process.env.HOSTNAME);
    let { pk, title, type, message_id, chat_id } = req.body;
    try {
        let apkPath = utils.getApkPathBasedOnPackageName(type)
        console.log(apkPath, '-----------------apkPath')
        let androidPublisher = await androidPublisherConn(pk);
        const appEdit = await androidPublisher.edits.insert({ packageName: pk });
        console.log(appEdit, 'appEdit')
        let editId = appEdit.data.id;

        // 上传APK到编辑会话
        const apkResponse = await androidPublisher.edits.bundles.upload({
            packageName: pk,
            editId: editId,
            media: {
                mimeType: 'application/octet-stream',
                body: fs.createReadStream(apkPath),
            },
        });
        console.log(apkResponse, 'apkResponse')
        const versionCode = apkResponse.data.versionCode;

        // 分配新的APK版本到内测轨道
        await androidPublisher.edits.tracks.update({
            packageName: pk,
            editId: editId,
            track: 'internal',
            requestBody: {
                releases: [{
                    versionCodes: [versionCode],
                    status: 'completed', // 或其他状态
                }],
            },
        });

        // 提交编辑会话
        await androidPublisher.edits.commit({
            packageName: pk,
            editId: editId,
        });

        console.log(`APK ${versionCode} 成功上传到内测轨道`);
        res.send({ code: 200, msg: "success" });

    } catch (error) {
        console.log(error);
        console.log("内测轨道部署失败:", error, "------------------------------err截至");
        //  发送失败的卡片
        if (error.response && error.response.data && error.response.data.error) {
            let betaError = gpBetaError(error.response.data.error.message);
            await msgUtils.sendMessage(
                req.body.chat_id,
                "interactive",
                betaError,
                token
            );
        } else {

        }

        res.send({ code: -1, msg: error.message });
    }
})

//接收发布灰度网页传递的参数  开始往线上推
router.post("/publishPostWithWebParams", async (req, res) => {
    let token = await msgUtils.getTenantAccessToken();
    const { pk, title, type, grayscale, message_id, chat_id } = req.body;
    //1. 先判断有没有被撤销
    let sql = `select * from js_app_msg_status where message_id = ?`;
    await pool.query(sql, message_id, async (err, result) => {
        if (err) return res.send(utils.returnData({ code: -1, err, req }));
        if (result.length != 0) {
            //已被撤回
            res.send({ code: 1, msg: "该版本已被撤回" });
            //  发送失败的卡片
            let proError = gpProMsg(
                `发布失败: ${title} - 灰度 (${grayscale}) 版本已被撤回`
            );
            await msgUtils.sendMessage(chat_id, "interactive", proError, token);
        } else {
            // 通过pk 判断 要往从哪个服务发起推送 pro
            let urlRequest = "";
            switch (pk) {
                case config.INS1:
                    urlRequest =
                        "http://45.76.212.42:5000/node/uploadPackage/selectGoogleApiByServerEnv";
                    break;
                case config.INS2:
                case config.ALL:
                case config.ALL2:
                case config.androidRoku2:
                case config.androidRoku3:
                case config.androidCalorie:
                case config.androidQr:
                case config.androidPrint:
                    urlRequest =
                        "http://170.187.230.149:5000/node/uploadPackage/selectGoogleApiByServerEnv";
                    break;
                case config.PDF:
                case config.INS3:
                case config.STEPCOUNTER:
                case config.WA2:
                case config.WA3:
                    urlRequest =
                        "http://172.104.35.128:5000/node/uploadPackage/selectGoogleApiByServerEnv";
                    break;
                case config.CALCULATOR:
                    urlRequest =
                        "https://tp.seamobitech.com/node/uploadPackage/selectGoogleApiByServerEnv";
                    break;
                case config.CHAT1:
                case config.CHAT2:
                case config.CHAT5:
                    urlRequest =
                        "http://139.177.190.31:5000/node/uploadPackage/selectGoogleApiByServerEnv";
                    break;
                default:
                    console.info("Package name does not match any known keys");
                    return null;
            }
            if (urlRequest) {
                try {
                    const response = await axios.post(urlRequest, req.body, {
                        headers: {
                            "Content-Type": "application/json",
                        },
                        timeout: 180000, // 设置超时时间为180秒
                    });
                    console.log(response, "response");
                    if (
                        response.data &&
                        response.data.code == 200 &&
                        response.data.msg == "success"
                    ) {
                        res.json({ code: 200, message: "success" });
                    } else {
                        res.json({ code: -1, message: response.data.msg }); //返回具体的失败响应
                    }
                } catch (error) {
                    console.error("request error please view log:", error.message);
                    return res.send({ code: -1, msg: error.message });
                }
            } else {
                console.error("urlRequest is empty.");
                return res.send({ code: -1, msg: "urlRequest is empty" });
            }
        }
    });
});
router.post("/selectGoogleApiByServerEnv", async (req, res) => {
    let token = await msgUtils.getTenantAccessToken();

    console.log(req.body, "我是selectGoogleApiByServerEnv--------我在", process.env.HOSTNAME);
    let { pk, title, type, grayscale, message_id, chat_id } = req.body;
    let regex = /\(([^)]+)\)/;
    let code = regex.exec(title)[1]; //code 是版本号 52.。53.。
    console.log(
        code,
        "-----------------------------拿到的code------------版本号"
    );
    try {
        let androidPublisher = await androidPublisherConn(pk);
        const appEdit = await androidPublisher.edits.insert({ packageName: pk });
        let editId = appEdit.data.id;

        // 获取所有轨道的信息
        const tracks = await androidPublisher.edits.tracks.list({
            packageName: pk,
            editId: editId,
        });
        console.log(pk, "pk-------------");
        console.log(editId, "editId-----------");
        console.log(tracks.data.tracks, "tracks-----------");
        // 查找版本号存在于哪个轨道
        let trackName = "";
        for (let track of tracks.data.tracks) {
            if (track.releases) {

                console.log(track.releases, 'track.releases');
                console.log(track.releases.versionCodes);
                let release = track.releases.find((r) => r.versionCodes && r.versionCodes.includes(code));
                if (release) {
                    trackName = track.track;
                    break;
                }
            }
        }

        // 根据版本所在轨道和状态决定后续操作
        if (trackName === "internal") {
            console.log(
                "从内侧轨道推到生产从内侧轨道推到生产从内侧轨道推到生产从内侧轨道推到生产"
            );
            // 从内侧轨道推到生产
            // 获取内测轨道的当前状态
            let testTrack = await androidPublisher.edits.tracks.get({
                packageName: pk,
                editId: editId,
                track: "internal",
            });
            // 如果内测轨道上有版本，推到正式轨道
            if (testTrack.data.releases && testTrack.data.releases.length > 0) {
                // 更新轨道以推广释放
                await androidPublisher.edits.tracks.update({
                    packageName: pk,
                    editId: editId,
                    track: "production",
                    requestBody: {
                        releases: [
                            {
                                versionCodes: [code], // 假定您想推广的版本是内测的第一个版本
                                status: "inProgress", // 标记发布状态为正在进行中
                                userFraction: grayscale,
                            },
                        ],
                    },
                });
                // 提交编辑
                let resultUpload = await androidPublisher.edits.commit({
                    packageName: pk,
                    editId: editId,
                });
                console.log(resultUpload, "resultUpload");
                console.log(
                    `从内侧轨道推到生产----成功-----------App promoted from Internal to Production track.`
                );

                let proSuccess = gpProMsgCard(req.body, title, grayscale, code);
                await msgUtils.sendMessage(chat_id, "interactive", proSuccess, token);
                res.send({ code: 200, msg: "success" });
            } else {
                console.log(
                    `从内侧轨道推到生产----失败-----------No releases found in Internal track to promote.`
                );
                res.send({ code: -1, msg: "部署失败！" });

                //失败卡片先不发----测试完解除注释
                // let proError1 = gpProMsg(
                //   `发布失败: ${title} - 灰度 (${grayscale})\n\n失败原因:\nNo releases found in Internal track to promote`
                // );
                // await msgUtils.sendMessage(chat_id, "interactive", proError1, token);
            }
        } else if (trackName === "production") {
            // 在生产轨道中执行增量更新
            // ...（执行增量逻辑）
            // 获取生产轨道的状态
            console.log(
                "在生产轨道中执行增量更新在生产轨道中执行增量更新在生产轨道中执行增量更新"
            );
            let productionTrack = await androidPublisher.edits.tracks.get({
                packageName: pk,
                editId: editId,
                track: "production",
            });

            // 找到对应版本的发布
            let releaseToUpdate = productionTrack.data.releases.find((r) =>
                r.versionCodes.includes(code)
            );

            if (releaseToUpdate && releaseToUpdate.status === "inProgress") {
                // 准备发布信息
                let releaseInfo = {
                    versionCodes: [code],
                    status: "inProgress",
                };
                // 如果 grayscale 不等于 1，则添加 userFraction 字段
                if (grayscale != 1) {
                    releaseInfo.userFraction = grayscale;
                    console.log(releaseInfo, '------------releaseInfo----------分阶段发布的releaseInfo')
                } else {
                    // 如果 grayscale 等于 1，则将状态设置为 completed
                    releaseInfo.status = "completed";
                    console.log(releaseInfo, '------------releaseInfo----------全量更新的releaseInfo')
                }
                // 更新生产轨道的发布信息
                const response = await androidPublisher.edits.tracks.update({
                    packageName: pk,
                    editId: editId,
                    track: "production",
                    requestBody: {
                        releases: [
                            releaseInfo
                        ],
                    },
                });

                // 打印响应数据，确认更新已成功
                console.log(
                    response.data,
                    "在生产轨道中执行增量更新---------打印响应数据，确认更新已成功"
                );

                // 提交编辑
                const commitResponse = await androidPublisher.edits.commit({
                    packageName: pk,
                    editId: editId,
                });

                console.log(commitResponse.data, "提交编辑");
                // 如果有必要，这里可以添加其他逻辑，比如发送通知等
                let proSuccess = gpProMsgCard(req.body, title, grayscale, code);
                await msgUtils.sendMessage(chat_id, "interactive", proSuccess, token);
                res.send({ code: 200, msg: "success" });
            } else {
                // 如果没有找到对应的分阶段发布，或者发布已经完成而不再是'inProgress'，处理这种情况
                console.error('没有找到对应的分阶段发布，或者版本状态不是"inProgress"');
                console.log("在生产轨道中执行增量更新--------- 确认更新已失败！！");
                // ...添加错误处理逻辑
                res.send({ code: -1, msg: "部署失败！" });

                //失败卡片先不发----测试完解除注释
                // let proError1 = gpProMsg(
                //   `发布失败: ${title} - 灰度 (${grayscale})\n\n失败原因:\n没有找到对应的分阶段发布，或者版本状态不是"inProgress"`
                // );
                // await msgUtils.sendMessage(chat_id, "interactive", proError1, token);
            }
        } else {
            // 版本未找到或在其他轨道
            // ...（处理逻辑）
        }
    } catch (error) {
        console.log(error);
        console.log("部署失败:", error, "------------------------------err截至");

        //失败卡片先不发----测试完解除注释
        // let proError1 = gpProMsg(
        //   `发布失败: ${title} - 灰度 (${grayscale})\n\n失败原因:\n${removeAnsiColorCodes(
        //     error.message
        //   )}`
        // );
        // await msgUtils.sendMessage(chat_id, "interactive", proError1, token);

        res.send({ code: -1, msg: error.message });
    }
});

//暂停阶段性发布
async function pausePeriodicRelease(
    type,
    pk,
    title,
    grayscale,
    code,
    chat_id,
    message_id,
    messageParse
) {
    let query = {
        type: type,
        pk: pk,
        title: title,
        grayscale: grayscale,
        code: code,
        chat_id: chat_id,
        message_id: message_id,
        messageParse: messageParse,
    };
    // 函数体，实现暂停阶段性发布的逻辑
    let urlRequest = "";
    switch (pk) {
        case config.INS1:
            urlRequest =
                "http://45.76.212.42:5000/node/uploadPackage/pausePeriodicReleaseFn";
            break;
        case config.INS2:
        case config.ALL:
        case config.ALL2:
        case config.androidRoku2:
        case config.androidRoku3:
        case config.androidCalorie:
        case config.androidQr:
        case config.androidPrint:
            urlRequest =
                "http://170.187.230.149:5000/node/uploadPackage/pausePeriodicReleaseFn";
            break;
        case config.PDF:
        case config.INS3:
        case config.STEPCOUNTER:
        case config.WA2:
        case config.WA3:
            urlRequest =
                "http://172.104.35.128:5000/node/uploadPackage/pausePeriodicReleaseFn";
            break;
        case config.CALCULATOR:
            urlRequest =
                "http://192.46.226.198:5000/node/uploadPackage/pausePeriodicReleaseFn";
            break;
        case config.CHAT1:
        case config.CHAT2:
        case config.CHAT5:
            urlRequest =
                "http://139.177.190.31:5000/node/uploadPackage/pausePeriodicReleaseFn";
            break;
        default:
            console.info("Package name does not match any known keys");
            return null;
    }
    if (urlRequest) {
        try {
            const response = await axios.post(urlRequest, query, {
                headers: {
                    "Content-Type": "application/json",
                },
                timeout: 180000, // 设置超时时间为180秒
            });
            console.log(response, "response");
            if (
                response.data &&
                response.data.code == 200 &&
                response.data.msg == "success"
            ) {
                res.json({ code: 200, message: "success" });
            } else {
                res.json({ code: -1, message: response.data.msg }); //返回具体的失败响应
            }
        } catch (error) {
            console.error("request error please view log:", error.message);
            return res.send({ code: -1, msg: error.message });
        }
    } else {
        console.error("urlRequest is empty.");
        return res.send({ code: -1, msg: "urlRequest is empty" });
    }
}
//暂停阶段性发布
router.post("/pausePeriodicReleaseFn", async (req, res) => {
    console.log(
        req.body,
        "我是pausePeriodicReleaseFn暂停阶段性发布--------我在",
        process.env.HOSTNAME
    );
    let token = await msgUtils.getTenantAccessToken();
    let { pk, title, type, grayscale, code, chat_id, message_id, messageParse } =
        req.body;
    try {
        let androidPublisher = await androidPublisherConn(pk);
        const appEdit = await androidPublisher.edits.insert({ packageName: pk });
        let editId = appEdit.data.id; //编辑id

        const response = await androidPublisher.edits.tracks.update({
            packageName: pk,
            editId: editId,
            track: "production", // 假设我们在暂停正式版轨道上的分阶段发布
            requestBody: {
                releases: [
                    {
                        versionCodes: [code], // 这里的99应该替换为你的应用实际的版本号
                        status: "halted",
                    },
                ],
            },
        });

        // 如果更新成功，提交修改
        await androidPublisher.edits.commit({
            packageName: pk,
            editId: editId,
        });
        console.log(response, "------------------暂停阶段性发布成功");

        // //先更新卡片使其不可点击
        //  let data = pauseCardDataTwo(messageParse);
        //  // 更新卡片内容 使按钮不可点击
        //  await msgUtils.updateCardDetails(
        //    token,
        //    data,
        //    message_id
        //  );

        let proSuccess = gpPauseCard(title);
        await msgUtils.sendMessage(chat_id, "interactive", proSuccess, token);
        res.send({ code: 200, msg: "success" });
    } catch (error) {
        console.log(error);
        console.log("暂停失败:", error, "------------------------------err截至");

        //失败卡片先不发----测试完解除注释
        // let proError1 = gpProMsg(
        //   `暂停分阶段发布失败: ${title} - 灰度 (${grayscale})\n\n失败原因:\n${removeAnsiColorCodes(
        //     error.message
        //   )}`
        // );
        // await msgUtils.sendMessage(chat_id, "interactive", proError1, token);

        res.send({ code: -1, msg: error.message });
    }
});

router.post('/decrypt', (req, res) => {
    console.log('injinjin')
    console.log(decrypt('4720e97a6cd728cf15584a70536074035128335bb17740700a209c504283f8e768bd620bcbd9f9dc94e474da9e9bb62cdba979018ddbcdc4', config.cryptoKey, config.cryptoIv))
})

// App 更新数量接口计算
//定时任务更新的时候先查询是不是等100,先发通知,后把status=1
router.post("/calculateUpdateNumber", async (req, res) => {
    let result = req.query.code && req.query.code === "961234" ? false : true;
    let content = "";
    if (result) {
        try {
            let parseData = req.body.query;
            content = JSON.parse(decrypt(parseData, config.cryptoKey, config.cryptoIv));
        } catch (error) {
        }
    } else {
        content = req.body.query;
    }
    let { packageName, ver } = content;
    if (!packageName || !ver)
        return res.send({ code: 1, message: "缺少必要参数" });
    let obj = {
        id: utils.createId(),
        package_name: packageName,
        type: utils.setTypeFromPackageName(packageName),
        ver: ver,
        create_time: utils.formatDate(new Date()),
        update_time: utils.formatDate(new Date()),
    };
    // 查询js_app_notice_node表同时符合包名和版本号的数据 
    let sqlFind = `SELECT * FROM js_app_notice_node WHERE package_name = ? AND ver = ?`;
    let findValues = [packageName, ver];

    try {
        let appNotices = await utils.query(sqlFind, findValues);
        let appNotice = appNotices[0]; // Assuming the query function returns an array of results
        // 如果没有对应的记录,就将其存入数据库
        if (!appNotice) {
            // 使用 createInsertSql 构建插入SQL语句
            const { text, values } = utils.createInsertSql("js_app_notice_node", obj);
            await utils.query(text, values);
            res.json({ code: 0, message: "操作成功" });
        } else {
            // appNotice.now_count == 100   到达阈值
            // ★ 根据包名动态设置阈值
            let threshold = (packageName == "print.smart.printer.pdf.docs.scanner") ? 50 : 100;

            // 达到阈值时触发
            if (appNotice.now_count == threshold) {
                checkThresholdLimit(appNotice);
             }
            // 更新进去让更新数量+1
            let sqlUpdate = `UPDATE js_app_notice_node 
                         SET now_count = now_count + 1, update_time = ? 
                         WHERE id = ?`;
            let updateValues = [utils.formatDate(new Date()), appNotice.id];
            await utils.query(sqlUpdate, updateValues);
            res.json({ code: 0, message: "操作成功" });
        }
    } catch (error) {
        res.json({ code: 1, message: error.message });
    }
});
// 加密函数
function encrypt(message, key, iv) {
    const keyHex = CryptoJS.enc.Utf8.parse(key);
    const ivHex = CryptoJS.enc.Utf8.parse(iv);
    const encrypted = CryptoJS.DES.encrypt(message, keyHex, {
        iv: ivHex,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7,
    });
    return encrypted.toString();
}

// 解密函数
function decrypt(ciphertext, key, iv) {

    const keyHex = CryptoJS.enc.Utf8.parse(key);
    const ivHex = CryptoJS.enc.Utf8.parse(iv);
    const decrypted = CryptoJS.DES.decrypt(
        {
            ciphertext: CryptoJS.enc.Base64.parse(ciphertext),
        },
        keyHex,
        {
            iv: ivHex,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7,
        }
    );
    return decrypted.toString(CryptoJS.enc.Utf8);
}
async function processFullUpload({ filePath, fileName, uploaderName, content }) {
    let AppPackageUpload = {};
    let dot = utils.getSubstringAfterLastDot(fileName);
    if (dot == "ipa") {
        try {
            const parser = new AppInfoParser(path.join(filePath));

            let result = await parser.parse();
            AppPackageUpload.id = utils.createId();
            console.log(AppPackageUpload.id, '---------AppPackageUpload.id')

            AppPackageUpload.create_by = uploaderName;
            AppPackageUpload.update_by = uploaderName;
            AppPackageUpload.create_date = utils.formatDate(new Date());
            AppPackageUpload.update_date = utils.formatDate(new Date());
            AppPackageUpload.version = result.CFBundleShortVersionString;
            AppPackageUpload.version_code = result.CFBundleVersion;
            AppPackageUpload.type = utils.setTypeFromPackageName(result.CFBundleName);
            console.log(AppPackageUpload.type, '---------AppPackageUpload.type')

            let iosName = AppPackageUpload.type === 'seamobitechRemote' ? 'roku' : AppPackageUpload.type;
            AppPackageUpload.title = `${iosName}-debug-${result.CFBundleShortVersionString}(${result.CFBundleVersion})`;
            AppPackageUpload.package_name = result.CFBundleIdentifier;
            AppPackageUpload.content = content;
            AppPackageUpload.env = dot;
            // 上传逻辑
            let urlRequest = utils.getServerEndpointByType(AppPackageUpload.type, AppPackageUpload.type + '.ipa')
            let uploadResponse = await uploadFileToServer(urlRequest, filePath);
            // 入库
            const { text, values } = utils.createInsertSql("js_app_package_upload", AppPackageUpload);
            let dbresult = await utils.query(text, values);
            if (dbresult.affectedRows !== 1)
                throw new Error("数据库写入失败");
            // 回调
            debugNotice(AppPackageUpload.type, AppPackageUpload.title, AppPackageUpload.content);
        } catch (e) {
            console.error("parser.parse异常", e);
            throw e; // 可以往上抛，也可以return error对象，看你需要
        }

        
    }
    else if (dot == "apk") {
        const parser = new AppInfoParser(path.join(filePath));
        let result = await parser.parse();
        AppPackageUpload.id = utils.createId();
        AppPackageUpload.create_by = uploaderName;
        AppPackageUpload.update_by = uploaderName;
        AppPackageUpload.create_date = utils.formatDate(new Date());
        AppPackageUpload.update_date = utils.formatDate(new Date());
        AppPackageUpload.package_name = result.package;
        AppPackageUpload.version = result.versionName;
        AppPackageUpload.version_code = result.versionCode;
        AppPackageUpload.type = utils.setTypeFromPackageName(result.package);
        AppPackageUpload.content = content;
        AppPackageUpload.env = dot;
        AppPackageUpload.title = `${AppPackageUpload.type}-debug-${result.versionName}(${result.versionCode})`;
        let urlRequest = utils.getServerEndpointByType(AppPackageUpload.type, AppPackageUpload.type + '.apk')
        let uploadResponse = await uploadFileToServer(urlRequest, filePath);
        // 入库
        const { text, values } = utils.createInsertSql("js_app_package_upload", AppPackageUpload);
        let dbresult = await utils.query(text, values);
        if (dbresult.affectedRows !== 1)
            throw new Error("数据库写入失败");
        debugNotice(AppPackageUpload.type, AppPackageUpload.title, AppPackageUpload.content);
    }
    else if (dot == "aab") {
        // aab用 bundletool 解析
        let stdout = await new Promise((resolve, reject) => {
            exec(`bundletool dump manifest --bundle="${filePath}"`, (err, stdout, stderr) => {
                if (err) return reject(err);
                resolve(stdout);
            })
        });
        const packageMatch = stdout.match(/package="([^"]+)"/);
        const versionCodeMatch = stdout.match(/versionCode="(\d+)"/);
        const versionNameMatch = stdout.match(/versionName="([^"]+)"/);
        const packageName = packageMatch ? packageMatch[1] : null;
        const versionCode = versionCodeMatch ? versionCodeMatch[1] : null;
        const versionName = versionNameMatch ? versionNameMatch[1] : null;

        AppPackageUpload.id = utils.createId();
        AppPackageUpload.create_by = uploaderName;
        AppPackageUpload.update_by = uploaderName;
        AppPackageUpload.create_date = utils.formatDate(new Date());
        AppPackageUpload.update_date = utils.formatDate(new Date());
        AppPackageUpload.package_name = packageName;
        AppPackageUpload.version = versionName;
        AppPackageUpload.version_code = versionCode;
        AppPackageUpload.type = utils.setTypeFromPackageName(packageName);
        AppPackageUpload.content = content;
        AppPackageUpload.env = dot;
        AppPackageUpload.title =
            `${AppPackageUpload.type}-release-${versionName}(${versionCode})`;

        let urlRequest = utils.getServerEndpointByType(AppPackageUpload.type, 'app-release.aab')
        let uploadResponse = await uploadFileToServer(urlRequest, filePath);
        // 入库
        const { text, values } = utils.createInsertSql("js_app_package_upload", AppPackageUpload);
        let dbresult = await utils.query(text, values);
        if (dbresult.affectedRows !== 1)
            throw new Error("数据库写入失败");
        // 通知
        submitFirstReviewRequest(
            utils.getGroupIdByType(AppPackageUpload.type),
            AppPackageUpload.type,
            AppPackageUpload.package_name,
            AppPackageUpload.title,
            AppPackageUpload.content
        );
    } else {
        throw new Error(`不支持的文件类型: .${dot}`);
    }
}
module.exports = router;
